( function() {
	// region util
	// 断言,用于抛出不可恢复错误
	function assert( flag, msg ) {
		if ( !flag ) throw new Error( msg );
	}

	// 遍历
	function loop( t, func ) {
		var i = 0;
		for ( i = 0; i !== t; ++i ) {
			func( i );
		}
	}

	// 遍历数组
	function eachArray( array, func ) {
		var i, len;
		for ( i = 0, len = array.length; i !== len; ++i ) {
			func( array[i], i );
		}
	}

	// 遍历字符串
	function eachString( string, func ) {
		var i, len;
		for ( i = 0, len = string.length; i !== len; ++i ) {
			func( string.charCodeAt( i ), i );
		}
	}

	function top( array ) {
		return array[array.length - 1];
	}

	// 使用字符数组创建一个JavaScript字符串
	function charArrayToStinrg( charArray ) {
		return String.fromCharCode.apply( String, charArray );
	}

	// 枚举字符串,给定一个枚举和枚举值,返回该枚举的字符串
	function enumString( en, enValue ) {
		var key = null;
		for ( key in en ) {
			if ( en[key] === enValue ) {
				return key;
			}
		}
		return null;
	}

	// 计算一个枚举的长度
	function enumLength( en ) {
		var num = 0;
		for ( key in en ) {
			++num;
		}
		return num;
	}

	// 枚举集合,根据枚举值数组构造一个集合,返回一个函数,用于判断一个枚举值是否属于这个集合
	function EnumCollection( en, envs ) {
		// 构建一个枚举数组,并将枚举值对应的位置填为true
		var enumMaps = Array( enumLength( en ) );
		eachArray( envs, function( env ) {
					enumMaps[env] = true;
				} );

		return function( env ) {
			return enumMaps[env] === true;
		};
	}

	// 根据字符串制作一个ascii表,返回一个函数,用来判断一个字符是否属于这个ascii表
	function AsciiMap( string ) {
		// 一个ascii表是一个bool[128]
		var asciiMaps = Array( 128 );
		eachString( string, function( ch ) {
					assert( ch < 128, "Asciimap only receives ascii char" );
					asciiMaps[ch] = true;
				} );

		return function( ch ) {
			return ch < 128 && ch >= 0 && asciiMaps[ch] === true;
		};
	}

	// 从字符串中获取字符编码
	function charCode( str ) {
		return str.charCodeAt( 0 );
	}

	// 字典转化为数组
	function dictToArray( dict ) {
		var key = null, retVal = Array();
		for ( key in dict ) {
			retVal.push( dict[key] );
		}
		return retVal;
	}

	// 字符常量
	var Slash = charCode( '\\' );
	var SQuote = charCode( "'" );
	var DQuote = charCode( '"' );
	var Dot = charCode( "." );

	// 字符判断函数
	function isLowerCase( ch ) {
		return ch >= 0x61 && ch <= 0x7A;
	}

	function isDigit( ch ) {
		return ch >= 0x30 && ch <= 0x39;
	}

	var isAlphaDigit = AsciiMap( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" );
	var isTokenChar = AsciiMap( "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" );
	// endregion

	// region 解析器部分
	// region 公共部分
	// 错误编号
	var ParseError = {
		UnexpectedEOF : 0,
		InvalidEscape : 1,
		InvalidChar : 2,
		InvalidNumber : 3,
		UnexpectedWord : 4,
		UnrecognisedMark : 5,
		ErrorExpr : 6,
		InvalidOperationType : 7,
		InvalidLeftValue : 8,
		UndefinedID : 9
	};

	// 抛出一个阅读错误
	function ReadError( errorNumber, errorValue ) {
		return {
			errorNumber : errorNumber,
			errorValue : errorValue
		};
	}

	// 词的类型,除了id,字符串,字符和数字外,每个关键字和符号各占一个类型,此外空白符和注释也在其中
	var WordType = {
		ID : 0,
		IF : 1,
		FOR : 2,
		WHILE : 3,
		GREAT : 4, // >
		SHIFT_RIGHT : 5, // >>
		SHIFT_RIGHT_LOGIC : 6, // >>>
		SHIFT_RIGHT_ASSIGN : 7, // >>=
		SHIFT_RIGHT_LOGIC_ASSIGN : 8, // >>>=
		LINE_ANNOTATION : 9,
		BLOCK_ANNOTATION : 10,
		STRING : 11,
		CHAR : 12,
		BLANK : 13,
		DECIMAL : 14,
		OCTAL : 15,
		HEX : 16,
		BINARY : 17,
		DOUBLE : 18,
		EOF : 19,
		LESS : 20, // <
		SHIFT_LEFT : 21, // <<
		SHIFT_LEFT_ASSIGN : 22, // <<=
		ADD : 23,
		INC : 24,
		SUB : 25,
		DEC : 26,
		LEFT_SMALL : 27,
		RIGHT_SMALL : 28,
		LEFT_MID : 29,
		RIGHT_MID : 30,
		LEFT_BIG : 31,
		RIGHT_BIG : 32,
		WAVE : 33,
		NOT : 34,
		PERCENT : 35,
		XOR : 36,
		AND : 37,
		BIT_AND : 38,
		MUL : 39,
		OR : 40,
		BIT_OR : 41,
		ASSIGN : 42,
		EQUAL : 43,
		NOT_EQUAL : 44,
		DIV : 45,
		QUESTION : 46,
		COLON : 47,
		SEMI : 48,
		GREAT_EQUAL : 49,
		LESS_EQUAL : 50,
		COMMA : 51,
		VAR : 52
	};
	var WordTypeLength = enumLength( WordType );

	// 关键词,举例kw( "if", wt.IF )
	function kw( str, type ) {
		return {
			string : str,
			type : type
		};
	}
	var mk = kw, wt = WordType;

	// 词法类型枚举,用于制作可装配词阅读器
	var LexType = {
		Token : 0,
		Value : 1
	};

	// zach的关键词和注释
	var ZachKeyword = [kw( "if", wt.IF ), kw( "while", wt.WHILE ), kw( "for", wt.FOR ), kw( "var", wt.VAR )];
	var ZachAnnotation = [mk( "/*a*/", wt.BLOCK_ANNOTATION ), mk( "//a\n", wt.LINE_ANNOTATION )];

	// Zach的所有符号
	var ZachMarks = {
		Great : mk( ">", wt.GREAT ),
		ShiftRight : mk( ">>", wt.SHIFT_RIGHT ),
		GreatEqual : mk( ">=", wt.GREAT_EQUAL ),
		ShiftRightLogic : mk( ">>>", wt.SHIFT_RIGHT_LOGIC ),
		ShiftRightAssign : mk( ">>=", wt.SHIFT_RIGHT_ASSIGN ),
		ShiftRightLogicAssign : mk( ">>>=", wt.SHIFT_RIGHT_LOGIC_ASSIGN ),
		Wave : mk( "~", wt.WAVE ),
		Not : mk( "!", wt.NOT ),
		NotEqual : mk( "!=", wt.NOT_EQUAL ),
		Precent : mk( "%", wt.PERCENT ),
		Xor : mk( "^", wt.XOR ),
		BitAnd : mk( "&", wt.BIT_AND ),
		And : mk( "&&", wt.AND ),
		Mul : mk( "*", wt.MUL ),
		LeftSmall : mk( "(", wt.LEFT_SMALL ),
		RightSmall : mk( ")", wt.RIGHT_SMALL ),
		Sub : mk( "-", wt.SUB ),
		Dec : mk( "--", wt.DEC ),
		Add : mk( "+", wt.ADD ),
		Inc : mk( "++", wt.INC ),
		LeftBig : mk( "{", wt.LEFT_BIG ),
		RightBig : mk( "}", wt.RIGHT_BIG ),
		LeftMid : mk( "[", wt.LEFT_MID ),
		RightMid : mk( "]", wt.RIGHT_MID ),
		BitOr : mk( "|", wt.BIT_OR ),
		Or : mk( "||", wt.OR ),
		Colon : mk( ":", wt.COLON ),
		Semi : mk( ";", wt.SEMI ),
		Less : mk( "<", wt.LESS ),
		LessEqual : mk( "<=", wt.LESS_EQUAL ),
		ShiftLeft : mk( "<<", wt.SHIFT_LEFT ),
		ShiftLeftAssign : mk( "<<=", wt.SHIFT_LEFT_ASSIGN ),
		Comma : mk( ",", wt.COMMA ),
		Question : mk( "?", wt.QUESTION ),
		Assign : mk( "=", wt.ASSIGN )
	};

	// 转义表
	function EscapeMap( pairs ) {
		var retVal = {};
		eachArray( pairs, function( pair ) {
					retVal[charCode( pair.source )] = charCode( pair.target );
				} );
		return retVal;
	}

	// 转义配对
	function EscapePair( source, target ) {
		return {
			source : source,
			target : target
		};
	}

	var ep = EscapePair;
	var ecMap = EscapeMap( [ep( "\\", "\\" ), ep( "n", "\n" ), ep( "t", "\t" ), ep( "'", "'" ), ep( '"', '"' )] ); // 转义字符表
	var MarkString = "~!@#$%^&*()-+={}[]|\\<,>.?/:;"; // 符号字符串
	var isBlankChars = AsciiMap( "\t\n " ); // 空白符

	// 空白字符
	var isBlankWord = EnumCollection( wt, [wt.BLANK, wt.BLOCK_ANNOTATION, wt.LINE_ANNOTATION] );
	// endregion

	// region 词法部分
	// 构造一个词
	function Word( type, value ) {
		return {
			type : type,
			value : value === null ? null : charArrayToStinrg( value )
		};
	}

	// 根据关键字生成一个标记阅读器,标记包括名称和关键字,考虑效率问题,只支持小写的关键字
	function TokenReader( keyWords ) {
		// 标记树的类型部分使用了可空类型(在JavaScript中没有体现)
		var tokenTree = {
			next : Array( 26 ),
			type : null
		}; // 标记树

		// 遍历所有的关键字
		eachArray( keyWords, function( keyWord ) {
					var curNode = tokenTree; // 当前节点
					var keyStr = keyWord.string;

					// 遍历字符串
					eachString( keyStr, function( ch ) {
								// 取出字符,判断是否是小写,若不是则异常
								assert( isLowerCase( ch ), "Keyword must be lowercase" );

								ch = ch - 0x61; // 映射到0-25

								// 下个路径节点为空,创造节点
								if ( curNode.next[ch] === undefined ) {
									curNode.next[ch] = {
										next : Array( 26 ),
										type : null
									};
								}
								curNode = curNode.next[ch];
							} );

					// 判断是否有重复的关键字,若有则异常
					assert( curNode.type === null, "Reduplicate keyword" );

					// 设置该条路径的type
					curNode.type = keyWord.type;
				} );

		return function( stringReader ) {
			var ch, value = Array(), curNode = tokenTree, isKeyword = true;

			while ( true ) {
				ch = stringReader.cur(); // 读字符

				// 如果不是数字或字母,退出,根据当前节点的类型选择返回的是关键字还是id
				if ( !isTokenChar( ch ) ) {
					return isKeyword && curNode.type !== null ? Word( curNode.type, null ) : Word( wt.ID, value );
				}
				else {
					// 如果目前仍属于关键字状态
					if ( isKeyword ) {
						// 如果ch是小写字母,并且,那么尝试走关键字表格
						if ( isKeyword && isLowerCase( ch ) && curNode.next[ch - 0x61] !== undefined ) {
							curNode = curNode.next[ch - 0x61];
						}
						// 否则置位
						else {
							isKeyword = false;
						}
					}

					// 更新值,吃字符
					value.push( ch );
					stringReader.eat();
				}
			}
		};
	}
	var readToken = TokenReader( ZachKeyword ); // 读标记

	// 制作一个符号阅读器,采用模式匹配的方式完成,模式使用'a'作为匹配符
	function MarkReader( patterns ) {
		var isValidChars = AsciiMap( MarkString.concat( "a\n" ) ); // 合法的模式字符,注意在常规符号中没有单引号,双引号和下划线

		// 状态表的类型部分使用了可空类型(在JavaScript中没有体现)
		var stateMap = {
			next : {},
			type : null
		};

		eachArray( patterns, function( pattern ) {
					var str = pattern.string, type = pattern.type;
					var curState = stateMap; // 当前状态是根状态
					var aState = null; // a状态

					// a必须在中间
					assert( str.charAt( 0 ) !== "a" && str.charAt( str.length - 1 ) !== "a", "Error mark-pattern" );

					eachString( str, function( ch ) {
								// 不能有非法字符
								assert( isValidChars( ch ), "Invalid mark-pattern char" );

								if ( ch === 0x61 ) {
									// 处理a
									assert( aState === null, "Error mark-pattern" );

									aState = curState;
								}
								else {
									// 处理其他字符
									if ( curState.next[ch] === undefined ) {
										curState.next[ch] = {
											next : {},
											type : null
										};
									}
									if ( aState !== null ) {
										curState.next[0x41] = aState;
									}
									curState = curState.next[ch];
								}
							} );

					// 不能有重复的模式,若有则异常
					assert( curState.type === null, "Reduplicate mark-pattern" );

					// 设置该条路径的type
					curState.type = type;
				} );

		return function( stringReader ) {
			var ch, curState = stateMap; // 当前状态

			// 爬状态表
			while ( true ) {
				ch = stringReader.cur(); // 读字符

				// 如果能往下走,往下走
				if ( curState.next[ch] !== undefined ) {
					curState = curState.next[ch];
				}
				// 如果不能走,看看有没全匹配
				else if ( curState.next[0x41] !== undefined ) {
					curState = curState.next[0x41];
				}
				// 否则跳出循环
				else {
					break;
				}

				stringReader.eat(); // 吃字符
			}

			// 没有匹配上任何符号,抛出错误
			if ( curState.type === null ) throw ReadError( ParseError.UnrecognisedMark );

			return Word( curState.type, null );
		};
	}

	// 制作一个词阅读器,指定要解析的词的类型(LexType)和符号,返回一个能解析这些词的阅读器
	// 词的类型包括:Token(名称和关键字),Value(字符串,整数和浮点数)
	// 总能处理空白符,行注释和列注释
	// 由于JavaScript的代码优化不够强劲,使用了保守的写法
	function LexReader( lexTypes, marks ) {
		// 读一个字符,并吃掉它
		function eatChar( stringReader ) {
			var ch = stringReader.cur(); // 读字符
			stringReader.eat(); // 吃掉刚读的字符

			// 如果是斜杠,处理转义
			if ( ch === Slash ) {
				ch = ecMap[stringReader.cur()]; // 解转义
				if ( retVal === undefined ) throw ReadError( ParseError.InvalidEscape ); // 若解失败,抛出错误
				stringReader.eat(); // 吃掉转义字符
			}

			// 读到-1,抛出错误
			if ( ch === -1 ) throw ReadError( ParseError.UnexpectedEOF );

			return ch;
		}

		var charBranchs = Array( 128 ); // 字符分支,即跳转表

		// 添加一个字符分支
		function addCharBranch( charString, stmt ) {
			eachString( charString, function( ch ) {
						// ch必须是ascii字符
						assert( ch >= 0 && ch < 128, "Char-branch only receives ascii char" );
						charBranchs[ch] = stmt; // 设置为响应
					} );
		}

		// 空白符分支
		addCharBranch( "\t\n ", function( stringReader ) {
					// 处理空白符
					stringReader.eat();

					// 吃掉所有空白符
					while ( isBlankChars( stringReader.cur() ) ) {
						stringReader.eat();
					}

					return Word( wt.BLANK, null );
				} );

		// 根据词的类型,添加Token分支Value分支
		eachArray( lexTypes, function( lexType ) {
					switch ( lexType ) {
						case LexType.Token :
							// Token分支
							addCharBranch( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_", readToken );
							break;
						case LexType.Value :
							// 字符分支
							addCharBranch( "'", function( stringReader ) {
										var value; // 字符的值

										stringReader.eat(); // 吃掉前单引号
										value = eatChar( stringReader ); // 吃字符
										if ( stringReader.cur() !== SQuote ) throw ReadError( ParseError.InvalidChar ); // 如果不是后单引号,抛出错误
										stringReader.eat(); // 吃掉后单引号

										return Word( wt.CHAR, [value] );
									} );

							// 字符串分支
							addCharBranch( '"', function( stringReader ) {
										var value = Array(); // 字符串的值

										stringReader.eat(); // 吃掉前双引号

										// 吃字符
										while ( stringReader.cur() !== DQuote ) {
											value.push( eatChar( stringReader ) );
										}

										stringReader.eat(); // 吃掉后双引号

										return Word( wt.STRING, value );
									} );

							// 数字分支
							addCharBranch( "0123456789", function( stringReader ) {
										var ch = stringReader.cur(); // 当前要处理的字符

										// 吃字符,并更新ch
										function eat() {
											stringReader.eat();
											ch = stringReader.cur();
										}

										var type, value = Array(); // 数字的类型,数字的值

										// 根据模式填充数组,模式是一个bool(char)函数,若填充失败,抛出异常
										function fillWith( isMatch, errorNumber ) {
											if ( !isMatch( ch ) ) throw ReadError( errorNumber );

											while ( isMatch( ch ) ) {
												value.push( ch );
												eat();
											}
										}

										// 处理数字
										if ( ch === 0x30 ) {
											// 开头是0,处理特殊格式
											eat(); // 吃掉0
											switch ( ch ) {
												// h和H,十六进制
												case 0x48 :
												case 0x68 :
													type = wt.HEX;
													break;
												// b和B,二进制
												case 0x42 :
												case 0x62 :
													type = wt.BINARY;
													break;
												// d和D,十进制
												case 0x44 :
												case 0x64 :
													type = wt.DECIMAL;
													break;
												// o和O,八进制
												case 0x4F :
												case 0x6F :
													type = wt.OCTAL;
													break;
												default :
													// 否则读到了0
													return Word( wt.DECIMAL, [0x30] );
											}
											eat(); // 吃掉特殊格式字符

											// 填充数字字母
											fillWith( isAlphaDigit, ParseError.InvalidNumber );
										}
										else {
											// 处理一般数字,包括十进制整数和浮点数
											// 读数字
											type = wt.DECIMAL; // 目前类型是十进制整数
											fillWith( isDigit, ParseError.InvalidNumber ); // 填充数字

											// 看能否连接小数点
											if ( ch === Dot ) {
												// 处理浮点
												value.push( ch );
												type = wt.DOUBLE; // 类型变为小数点
												eat(); // 吃掉小数点

												fillWith( isDigit, ParseError.InvalidNumber ); // 填充数字
											}

											// 看能否连e或者E
											if ( ch === 0x45 || ch === 0x65 ) {
												value.push( ch );
												type = wt.DOUBLE;
												eat(); // 吃掉e

												fillWith( isDigit, ParseError.InvalidNumber ); // 填充数字
											}
										}

										return Word( type, value );
									} );
							break;
					}
				} );

		// 添加符号分支
		addCharBranch( MarkString, MarkReader( marks === undefined ? ZachAnnotation : ZachAnnotation.concat( marks ) ) );

		function readWord( stringReader ) {
			// 根据当前读出的字符进行分支
			var ch, branch;

			while ( true ) {
				ch = stringReader.cur();

				// 是ascii字符,查表跳转
				if ( ch >= 0 && ch < 128 ) {
					branch = charBranchs[ch]; // 取出分支
					if ( branch !== undefined ) {
						return branch( stringReader );
					}
				}

				// 处理EOF
				if ( ch === -1 ) {
					return Word( wt.EOF, null );
				}
			}

			// 什么都不是,抛出错误
			throw ReadError( ParseError.UnexpectedWord );
		}

		return function( stringReader ) {
			var retVal;
			while ( true ) {
				retVal = readWord( stringReader );
				if ( !isBlankWord( retVal.type ) ) {
					return retVal;
				}
			}
		};
	}
	var readWord = LexReader( [LexType.Token, LexType.Value], dictToArray( ZachMarks ) ); // 全解析器
	// endergion
	// endregion

	// region 语法部分

	var IDCategory = {
		Var : 0
	};

	// 类型种类
	var TypeCategory = {
		Int : 0,
		Double : 1,
		Long : 2,
		String : 3,
		Array : 4,
		Struct : 5,
		Enum : 6,
		Union : 7,
		Bool : 8
	};

	// 基本类型种类
	var isBasicTypeCategory = EnumCollection( TypeCategory, [TypeCategory.Int, TypeCategory.Bool, TypeCategory.Double, TypeCategory.Long, TypeCategory.String] );

	function isSameType( type1, type2 ) {
		if ( type1 === type2 ) {
			return true;
		}
		else if ( type1.category !== type2.category ) {
			return false;
		}
		else {
			if ( isBasicTypeCategory( type1.category ) ) {
				return true;
			}
			return false;
		}
	}

	// 基本类型,指整数,浮点等不能拆分的类型
	function BasicType( typeCategory ) {
		return {
			category : typeCategory
		};
	}

	var Int = BasicType( TypeCategory.Int );
	var Double = BasicType( TypeCategory.Double );
	var Bool = BasicType( TypeCategory.Bool );

	// 表达式类型
	var ExprCategory = {
		Literal : 0,
		KnownVar : 1,
		BuiltInBinaryOperation : 2,
		BuiltInTernaryOperation : 3,
		BuiltInUnaryOperation : 4
	};

	// 判断一个表达式是否是已知的
	var isExprKnown = EnumCollection( ExprCategory, [ExprCategory.Literal, ExprCategory.KnownVar, ExprCategory.BuiltInBinaryOperation,
					ExprCategory.BuiltInTernaryOperation, ExprCategory.BuiltInUnaryOperation] );

	// 赋值性
	var AssignType = {
		LeftValue : 0,
		RightValue : 1
	};

	function exptect( word, expectedWordType, errNo, errMsg ) {
		if ( word.type !== expectedWordType ) throw ReadError( errNo, errMsg );
		return word;
	}

	// 表达式机器状态
	var ExprMachineState = {
		Before : 0,
		After : 1
	};

	// 结合性
	var Associativity = {
		Left : 0,
		Right : 1
	};

	// 结合类型
	var CombineType = {
		Binary : 0,
		Ternary : 1
	};

	// Before状态类型
	var BeforeStateType = {
		Value : 0,
		Prefix : 1
	};

	// Before状态类型
	var AfterStateType = {
		Binary : 0,
		TernaryFirst : 1,
		TernarySecond : 2,
		Postfix : 3
	};

	// 机器的动作类型
	var ExprActionType = {
		Cal : 0,
		Push : 1
	};
	var EAT = ExprActionType;

	function ExprMaker( arg ) {
		// Expr的解析
		// 1.有两种状态:一个是没有读到值实体的状态,也就是要读值实体的状态,称为Before态;另一个是读到了值实体的状态,称为After态
		// 2.在Before态下,可以读前缀和值实体,前缀总是单词,而值实体可以是词组,当读到前缀时,将前缀运算压入前缀栈,不切换状态
		// 3.当读到值实体时,切换状态到After态,并将值实体保存到curValue中,值实体可以是词组,但是必须是界词组
		// 4.在After态下,可以读后缀和连接符,后缀一般是词组,但是连接符总是单词,当读到后缀时,直接将后缀作用到curValue上,并将结果存为新的curValue,不切换状态
		// 5.当读到连接符时,根据读到的连接符和当前连接符栈栈顶(前一个连接符)进行动作,并切换状态到Before态

		var startWords = Array(); // 给以做起始词的词,即包括前缀以及prime的startWord

		var beforeState = Array( WordTypeLength ); // 根前缀状态表,处理前缀和值实体
		var afterState = Array( WordTypeLength ); // 根结合状态表,处理后缀和结合,后者包括二元操作符和三元操作符
		var combinePriority = Array( arg.combine.length ); // 结合符优先级表

		// 遍历结合符号的优先级表,创建子状态表,注意每一项又是一个数组
		// 结合符号总是孤立的词
		eachArray( arg.combine, function( combines, i ) {
					combinePriority[i] = Array(); // 填优先级队列

					// 遍历具体的优先级
					eachArray( combines.operator, function( combine, j ) {
								var state, state0, state1;

								if ( combine.type === CombineType.Binary ) {
									// 二元操作符只有一个状态
									state = {
										type : AfterStateType.Binary,
										word : combine.opWord,
										action : Array( WordTypeLength ),
										operation : combine.operation,
										assembler : combine.assembler
									};
									afterState[combine.opWord] = state;
									combinePriority[i].push( state );
								}
								else {
									// 三元操作符有两个状态
									state0 = {
										type : AfterStateType.TernaryFirst,
										word : combine.opWord[0],
										pair : combine.opWord[1],
										action : Array( WordTypeLength )
									};
									afterState[combine.opWord[0]] = state0;
									combinePriority[i].push( state0 );

									state1 = {
										type : AfterStateType.TernarySecond,
										word : combine.opWord[1],
										pair : combine.opWord[0],
										operation : combine.operation,
										assembler : combine.assembler
									};
									afterState[combine.opWord[1]] = state1;
									combinePriority[i].push( state1 );
								}
							} );
				} );

		// 结合状态计算
		// 1.正读取的二元操作符soruce遇上了栈顶的二元操作符target
		// a.如果s的优先级高于t,压栈
		// b.如果s和t是同一个优先级,右结合则压栈,结束,左结合则计算
		// c.如果s的优先级低于t,计算
		// 2.正读取的二元操作符遇上了栈顶的三元操作符,压栈
		// 3.正读取的二元操作符遇到了空,压栈
		// 4.正读取的三元操作符第二符,计算到对应的第一符为止,弹出第一符,压结果
		// 5.正读取的三元操作符第一符source,遇上了栈顶的操作符三元操作符第二符或二元操作符target
		// a.如果s的优先级高于t,压栈
		// b.如果s和t是同一个优先级,右结合则压栈,结束,左结合则计算
		// c.如果s的优先级低于t,计算
		// 6.正读取的三元操作符第一符source遇上了空,压栈
		// 7.读到了非连接符,遇上了操作符target
		// a.target是三元操作符的第一符,出错
		// b.否则继续计算到遇到空

		// 遍历所有操作符
		function eachOperator( func ) {
			eachArray( arg.combine, function( targets, targetPriority ) {
						eachArray( targets.operator, function( target ) {
									func( target, targetPriority, targets.associativity );
								} );
					} );
		}

		// 一般的结合
		function normalCombine( sp, tp, asso ) {
			return sp < tp ? EAT.Push : sp === tp ? asso === Associativity.Left ? EAT.Cal : EAT.Push : EAT.Cal;
		}

		// 再遍历二元优先级表,根据优先级和结合性等属性来计算动作
		// 优先级数字小为高
		eachArray( combinePriority, function( sources, sp ) {
					eachArray( sources, function( source ) {
								switch ( source.type ) {
									case AfterStateType.Binary :
										eachOperator( function( target, tp, asso ) {
													if ( target.type === CombineType.Binary ) {
														source.action[target.opWord] = normalCombine( sp, tp, asso );
													}
													else {
														source.action[target.opWord[0]] = EAT.Push;
														source.action[target.opWord[1]] = EAT.Push;
													}
												} );
										break;
									case AfterStateType.TernaryFirst :
										eachOperator( function( target, tp, asso ) {
													if ( target.type === CombineType.Binary ) {
														source.action[target.opWord] = normalCombine( sp, tp, asso );
													}
													else {
														source.action[target.opWord[0]] = EAT.Push;
														source.action[target.opWord[1]] = normalCombine( sp, tp, asso );
													}
												} );
										break;
								}
							} );
				} );

		// 处理prime
		eachArray( arg.prime, function( prime ) {
					beforeState[prime.startWord] = {
						type : BeforeStateType.Value,
						reader : prime.reader
					};
					startWords.push( prime.startWord );
				} );

		// 处理前缀
		eachArray( arg.prefix, function( prefix ) {
					beforeState[prefix.opWord] = {
						type : BeforeStateType.Prefix,
						operation : prefix.operation
					};
					startWords.push( prefix.opWord );
				} );

		// 处理后缀
		eachArray( arg.posfix, function( postfix ) {
					afterState[postfix.startWord] = {
						type : AfterStateType.Postfix,
						reader : postfix.reader
					};
				} );

		return {
			reader : function( startWord, stringReader, context ) {
				var curWord, curWordType; // 当前读到的词
				var machineState = ExprMachineState.Before; // 初始的机器状态是Before态
				var valueStack = Array(), opStack = Array(), prefixStack = Array(), opTop; // 值栈,运算符栈
				var state, curValue = null; // 当前的状态和当前的值
				var hasStarted = startWord === null;

				// 切换到before态
				function toBefore() {
					var topPrefix;
					// 首先计算所有的前缀
					while ( prefixStack.length !== 0 ) {
						topPrefix = prefixStack.pop();
						curValue = topPrefix.operation( curValue );
					}

					valueStack.push( curValue );
					machineState = ExprMachineState.Before;
				}

				// 进行运算
				function doOperation( operator ) {
					var lhs, rhs, op1, op2, op3; // 操作数

					switch ( operator.type ) {
						case AfterStateType.Binary :
							rhs = valueStack.pop();
							lhs = valueStack.pop();
							valueStack.push( operator.operation( lhs, rhs ) );
							opStack.pop();
							break;
						case AfterStateType.TernarySecond :
							op3 = valueStack.pop();
							op2 = valueStack.pop();
							op1 = valueStack.pop();
							valueStack.push( operator.operation( op1, op2, op3 ) );
							opStack.pop();
							break;
						case AfterStateType.TernaryFirst :
							throw ReadError( ParseError.ErrorExpr, "Unexptected matched tennery operator, lossing " + enumString( wt, operator.pair ) );
					}
				}

				while ( true ) {
					// 读当前的词,并取出它的类型,根据有没有读startWord进行分支
					if ( hasStarted ) {
						curWord = readWord( stringReader );
					}
					else {
						curWord = startWord;
						hasStarted = true;
					}

					curWordType = curWord.type;

					// 根据当前的状态进行分支
					if ( machineState === ExprMachineState.Before ) {
						// Before态,读值实体和前缀
						state = beforeState[curWordType];

						if ( state === undefined )
							throw ReadError( ParseError.ErrorExpr, "Unexptected " + enumString( wt, curWordType ) + " in expression, expect prefix or value" );
						switch ( state.type ) {
							case BeforeStateType.Value :
								// 读到了中心词,存到curValue中,切换状态
								curValue = state.reader( curWord, stringReader, context );
								machineState = ExprMachineState.After;
								break;
							case BeforeStateType.Prefix :
								// 读到了前缀,存入栈中,不切换状态
								prefixStack.push( state );
								break;
						}
					}
					else {
						state = afterState[curWordType];
						if ( state === undefined ) {
							toBefore(); // 切换到before态

							// 读到了非连接符,计算全部,结束表达式读取,返回结果
							while ( opStack.length !== 0 ) {
								doOperation( top( opStack ) );
							}

							return {
								extraWord : curWord,
								value : valueStack[0]
							};
						}

						switch ( state.type ) {
							case AfterStateType.Binary :
							case AfterStateType.TernaryFirst :
								toBefore(); // 切换到before态
								while ( true ) {
									if ( opStack.length === 0 ) {
										// op栈为空,压入当前状态
										opStack.push( state );
										break;
									}
									else {
										// 否则取出栈顶进行操作
										opTop = top( opStack );
										if ( state.action[opTop.word] === ExprActionType.Cal ) {
											doOperation( opTop );
										}
										else {
											opStack.push( state );
											break;
										}
									}
								}
								break;
							case AfterStateType.TernarySecond :
								toBefore(); // 切换到before态
								while ( true ) {
									if ( opStack.length === 0 ) {
										// 栈读空仍未匹配到说明错误
										throw ReadError( ParseError.ErrorExpr, "Unexptected matched tennery operator, lossing " + enumString( wt, state.pair ) );
									}
									else {
										// 一直运算到读出对应的操作符
										opTop = top( opStack );
										if ( opTop.word === state.pair ) {
											// 读到了对应的操作符,弹出对应的操作符并压入当前的操作符
											opStack.pop();
											opStack.push( state );
											break;
										}
										else {
											doOperation( opTop );
										}
									}
								}
								break;
							case AfterStateType.Postfix :
								// 读到后缀,不切换状态,直接作用到curValue上
								curValue = state.reader( curWord, stringReader, context, curValue );
								break;
						}
					}
				}
			},
			startWords : startWords
		};
	}

	// 字面值类型
	function literal( type, value ) {
		return {
			category : ExprCategory.Literal,
			type : type,
			assignType : AssignType.RightValue,
			value : value
		};
	}

	// 整数字面值
	function IntReader( radix ) {
		return function( fisrtWord, stringReader, context ) {
			return literal( Int, parseInt( fisrtWord.value, radix ) );
		};
	}

	// 二元操作类型机器
	function binaryTypeMachine( arg ) {
		return function( lhs, rhs ) {
			var i, len;
			for ( i = 0, len = arg.length; i !== len; ++i ) {
				typeOp = arg[i];
				if ( isSameType( lhs.type, typeOp.type[0] ) && isSameType( rhs.type, typeOp.type[1] ) ) {
					return typeOp.operation( lhs, rhs );
				}
				throw ReadError( ParseError.InvalidOperationType );
			}
		};
	}

	// 整数四则运算的计算
	function FourOperations( operation ) {
		return binaryTypeMachine( [{
					type : [Int, Int],
					operation : function( lhs, rhs ) {
						return literal( Int, operation( lhs.value, rhs.value ) );
					}
				}] );
	}

	// 四则运算
	var oAdd = FourOperations( function( lhs, rhs ) {
				return lhs + rhs;
			} );
	var oSub = FourOperations( function( lhs, rhs ) {
				return lhs - rhs;
			} );
	var oMul = FourOperations( function( lhs, rhs ) {
				return lhs * rhs;
			} );
	var oDiv = FourOperations( function( lhs, rhs ) {
				return lhs / rhs;
			} );

	// 赋值运算
	var oAssign = function( lhs, rhs ) {
		lhs.value = rhs.value;
		return lhs;
	};

	function IDReader( arg ) {
		var idReaders = Array( enumLength( IDCategory ) ); // reader表
		var other = arg.other; // 其他路线

		eachArray( arg.main, function( idReader ) {
					idReaders[idReader.category] = idReader.reader;
				} );

		return function( startWord, stringReader, context ) {
			// 根据id的type取出对应的reader,若取到则调用,否则调用other
			var idWord = context.getID( startWord.value );
			var reader = idReaders[idWord.category];
			return ( reader === undefined ? other : reader )( idWord, stringReader, context );
		};
	}

	// 读表达式
	var readExpr = null;
	var readExprResult = ExprMaker( {
				prime : [{
							startWord : wt.OCTAL,
							reader : IntReader( 8 )
						}, {
							startWord : wt.DECIMAL,
							reader : IntReader( 10 )
						}, {
							startWord : wt.BINARY,
							reader : IntReader( 2 )
						}, {
							startWord : wt.HEX,
							reader : IntReader( 16 )
						}, {
							startWord : wt.LEFT_SMALL,
							reader : function( firstWord, stringReader, context ) {
								var readResult = readExpr( null, stringReader, context );
								if ( readResult.extraWord.type !== wt.RIGHT_SMALL ) throw ReadError( ParseError.ErrorExpr, "Error expression. Expected ')'." );
								return readResult.value;
							}
						}, {
							startWord : wt.ID,
							reader : IDReader( {
										main : [{
													category : IDCategory.Var,
													reader : function( idWord, stringReader, context ) {
														return idWord;
													}
												}],
										other : function( idWord, stringReader, context ) {
											throw ReadError( ParseError.UndefinedID );
										}
									} )
						}],
				prefix : [{
							opWord : wt.INC,
							operation : function( op ) {
								op.value += 1;
								return op;
							}
						}],
				posfix : [{
							startWord : wt.INC,
							reader : function( startWord, stringReader, context, op ) {
								var retVal = literal( Int, op.value );
								op.value += 1;
								return retVal;
							}
						}],
				combine : [{
							// 乘除
							associativity : Associativity.Left,
							operator : [{
										type : CombineType.Binary,
										opWord : wt.MUL,
										operation : oMul
									}, {
										type : CombineType.Binary,
										opWord : wt.DIV,
										operation : oDiv
									}]
						}, {
							// 加减
							associativity : Associativity.Left,
							operator : [{
										type : CombineType.Binary,
										opWord : wt.ADD,
										operation : oAdd
									}, {
										type : CombineType.Binary,
										opWord : wt.SUB,
										operation : oSub
									}]
						}, {
							// 三元操作符?:
							associativity : Associativity.Right,
							operator : [{
										type : CombineType.Ternary,
										opWord : [wt.QUESTION, wt.COLON],
										operation : function( op1, op2, op3 ) {
											return literal( ExprCategory.LInt, op1.value > 0 ? op2.value : op3.value );
										}
									}]
						}, {
							// 赋值
							associativity : Associativity.Right,
							operator : [{
										type : CombineType.Binary,
										opWord : wt.ASSIGN,
										operation : oAssign
									}]
						}]
			} );
	readExpr = readExprResult.reader;
	ExprStartWord = readExprResult.startWords;

	function scopeReader( arg ) {
		var main = Array( enumLength( WordType ) ); // reader表
		var other = arg.other; // 其他路线

		eachArray( arg.main, function( wordReader ) {
					if ( wordReader.startWord !== undefined ) {
						main[wordReader.startWord] = wordReader.reader;
					}
					else {
						eachArray( wordReader.startWords, function( startWord ) {
									main[startWord] = wordReader.reader;
								} );
					}
				} );

		return function( stringReader ) {
			var reader, startWord;
			while ( true ) {
				startWord = readWord( stringReader );

				if ( startWord.type === arg.endWord ) {
					return;
				}
				else {
					reader = main[startWord.type];
					( reader === undefined ? other : reader )( startWord );
				}
			}
		};
	};
	// endregion
	// endregion

	// region 测试部分
	// 最基本的字符串阅读器,只有cur和eat功能
	function StringReader( str ) {
		var pos = 0, len = str.length, ch = null;

		function eatChar() {
			if ( pos > len ) throw ReadError( ParseError.UnexpectedEOF );
			ch = pos === len ? -1 : str.charCodeAt( pos++ );
		}

		eatChar(); // 读第一个字符
		return {
			cur : function() {
				return ch;
			},
			eat : eatChar
		};
	}

	// 在文档上打印字符串
	function printLn( str ) {
		var div = document.createElement( "div" );
		div.innerHTML = str + "";
		document.body.appendChild( div );
	}

	function testRead( stringReader ) {
		var idMap = {};
		var context = {
			getID : function( name ) {
				return idMap[name];
			}
		};
		scopeReader( {
					main : [{
								startWord : wt.VAR,
								reader : function( startWord ) {
									var id = exptect( readWord( stringReader ), wt.ID, ParseError.UndefinedID );
									exptect( readWord( stringReader ), wt.ASSIGN, ParseError.UnexpectedWord );
									var exprReadResult = readExpr( null, stringReader, context );

									idMap[id.value] = exprReadResult.value;
									exptect( exprReadResult.extraWord, wt.SEMI, ParseError.UnexpectedWord );
								}
							}, {
								startWords : ExprStartWord,
								reader : function( startWord ) {
									var exprReadResult = readExpr( startWord, stringReader, context );
									exptect( exprReadResult.extraWord, wt.SEMI, ParseError.UnexpectedWord );
								}
							}, {
								startWord : wt.QUESTION,
								reader : function( startWord ) {
									var exprReadResult = readExpr( null, stringReader, context );
									exptect( exprReadResult.extraWord, wt.SEMI, ParseError.UnexpectedWord );
									printLn( exprReadResult.value.value + "" );
								}
							}],
					other : function( startWord ) {
						throw ReadError( ParseError.UnexpectedWord );
					},
					endWord : wt.EOF
				} )( stringReader );
	}

	// 创建一个按钮,方便延时调试
	function button( label, onClick ) {
		var btn = document.createElement( "button" );
		btn.innerHTML = label;
		btn.onclick = onClick;
		document.body.appendChild( btn );
	}

	window.onload = function() {
		var div = document.createElement( "div" );
		var ta = document.createElement( "textarea" ); // 创建一个文本框,用来输入代码
		div.appendChild( ta );
		ta.cols = 180;
		ta.rows = 20;
		ta.autofocus = true;
		ta.style.resize = "none";
		document.body.appendChild( div );

		button( "test", function() {
					var stringReader = StringReader( ta.value );
					try {
						testRead( stringReader );
					}
					catch ( e ) {
						printLn( enumString( ParseError, e.errorNumber ) + e.errorValue === undefined ? "" : " " + e.errorValue );
					}
				} );
	};
	// endregion
} )();